import { Menu } from "@/utils/Menu"

import { Group } from "@/js/components/Group"
import { LinkNodeLine } from "@/js/components/LinkNodeLine"
import { GraphView } from "@/js/components/GraphView"
import { GraphNode } from "../../GraphNode"

let global: {
    dragTarget?: LinkNode,
    drogTarget?: LinkNode,
    linkNodeLine?: LinkNodeLine
} = {}

export class LinkNode extends Group{
    bgColor = "#673ab7"
    targetData:{[k:string]: any} = { }
    graphView: GraphView
    graphNode: GraphNode
    private rules:( (linkNode:LinkNode)=>boolean )[] = []
    index = 0 // 0：出，1：进

    name?: string

    private count = 0
    maxCount = 1

    linkNodeLines: LinkNodeLine[] = []

    constructor(graphNode: GraphNode, graphView: GraphView ){
        super()
        this.graphView = graphView
        this.graphNode = graphNode

        this.setStyle({
            width: '10px',
            height: '10px',
            border: 'solid 1px ' + this.bgColor,
            zIndex: 1000
        })

        this.initEvent()

        this.addRule(()=>{
            return global.dragTarget?.index !== this.index  // 两个相连节点的index 不能相同，例如两个入节点不能相连
            && global.dragTarget !== this // 不能连接所属图形节点的任意子节点
            && global.dragTarget?.graphNode !== this.graphNode // 不能连接自己
            && this.count < this.maxCount // 连接数量已经用完
        })
    }

    setBgColor(color: string){
        this.bgColor = color
        this.setStyle({
            border: 'solid 1px ' + color,
        })
    }

    private initEvent(){
        this.addEventListener("mousedown", this.dragStart.bind(this) as any)

        this.addEventListener("mouseenter", () => {
            if(global.dragTarget &&  global.dragTarget !== this) {
                if((this.rules.map(rule=>rule(global.dragTarget as LinkNode)).indexOf(false) === -1)){
                    global.drogTarget = this
                    this.linkNodeEnter({
                        rule: true
                    })
                }
                else{
                    this.linkNodeEnter({
                        rule: false
                    })
                }
            }
        })

        this.addEventListener("mouseleave", () => {
            if(global.dragTarget && global.dragTarget !== this){
                if(global.drogTarget && global.drogTarget === this) {
                    delete global.drogTarget
                    this.linkNodeLeave({rule: true})
                }
                else{
                    this.linkNodeLeave({rule: false})
                }
            }
        })

        this.addEventListener("mouseup", () => {
            if(global.dragTarget && global.dragTarget !== this){
                if(global.drogTarget && global.drogTarget === this) {
                    this.linkNodeLeave({rule: true})
                }
                else{
                    this.linkNodeLeave({rule: false})
                }
            }
        })

        this.dragMoveBind = this.dragMove.bind(this)
        this.dragEndBind = this.dragEnd.bind(this)
    }

    dragStart(e: MouseEvent){
        if(this.count >= this.maxCount) return
        const viewReat =  this.graphView.getRect()
        const {left, top, width, height } = this.getRect()
        const x = left - viewReat.left + width / 2, y = top - viewReat.top + height / 2

        this.graphView.addEventListener("mousemove", this.dragMoveBind)
        this.graphView.addEventListener("mouseup", this.dragEndBind)
        
        global.dragTarget = this
        global.linkNodeLine = new LinkNodeLine()
        global.linkNodeLine.setStartPoint(x, y)
        global.linkNodeLine.setEndPoint(x, y)
        global.linkNodeLine.drawTarget(this.graphView)
        global.linkNodeLine.path.stroke(this.bgColor)

        this.active()

        e.stopPropagation()
        e.preventDefault()
    }

    dragMove({clientX, clientY}: MouseEvent){
        const viewReat =  this.graphView.getRect()
        if(this.index === 0){
            global.linkNodeLine && global.linkNodeLine.setEndPoint(clientX - viewReat.left, clientY - viewReat.top)
        }
        else{
            global.linkNodeLine && global.linkNodeLine.setStartPoint(clientX - viewReat.left, clientY - viewReat.top)
        }
    }

    dragEnd(){
        this.graphView.removeEventListener("mousemove", this.dragMoveBind)
        this.graphView.removeEventListener("mouseup", this.dragEndBind)

        if(!global.drogTarget){
            global.linkNodeLine?.removeTo()
            this.cancelActive()
        }
        else{
            this.linkNodeLines.push(global.linkNodeLine as LinkNodeLine)
            global.linkNodeLine?.path.pointerEvents('all')
            global.drogTarget.drog()

            this.linkNodeLineEvent()
            global.linkNodeLine?.setTarget(global.dragTarget as LinkNode, global.drogTarget as LinkNode)

            this.count++
            this.event.emit("link", {
                target: global.drogTarget
            })
        }
        
        global = {}
    }

    drog(){
        if(this.count >= this.maxCount) return
        this.linkNodeLines.push(global.linkNodeLine as LinkNodeLine)
        this.active()
        this.count++

        this.event.emit("link", {
            target: global.dragTarget
        })
        
    }

    linkNodeLineEvent(linkNodeLine_?: LinkNodeLine){
        const linkNodeLine = linkNodeLine_ || global.linkNodeLine as LinkNodeLine
        linkNodeLine.path.addEventListener("mousedown", ((e:MouseEvent)=>{
            const {clientX, clientY, button} = e
            if(button === 2){
                new Menu([
                    {
                        items:[
                            {
                                
                                name: "删除",
                                click({close}:any){
                                    linkNodeLine.del()
                                    close()
                                }
                            },
                        ]
                    }
                ]).show(clientX, clientY)
            }
        }) as any)

        linkNodeLine.path.addEventListener("mouseenter", ()=>{
            linkNodeLine.path.strokeWidth(4)
            linkNodeLine.path.stroke("#ffc107")
        })

        linkNodeLine.path.addEventListener("mouseleave", ()=>{
            linkNodeLine.path.strokeWidth(2)
            linkNodeLine.path.stroke(this.bgColor)
        })
    }

    setTargetData(targetData:object){
        this.targetData = targetData
    }

    setIndex(index: 0 | 1){
        this.index = index
    }

    update(){
        const viewReat =  this.graphView.getRect()
        const {width,height,left,top} = this.getRect()
        const x = left - viewReat.left + width  / 2
        const y = top - viewReat.top + height  / 2

        if(this.index === 0){
            this.linkNodeLines.forEach(item=>{
                item.setStartPoint(x, y)
            })
        }
        else{
            this.linkNodeLines.forEach(item=>{
                item.setEndPoint(x, y)
            })
        }
    }

    delLinkNodeLine(linkNodeLine:LinkNodeLine){
        const index = this.linkNodeLines.indexOf(linkNodeLine)
        this.linkNodeLines.splice(index, 1)
        this.cancelActive()

        this.event.emit("unlink", {
            target: this
        })
        
        this.count--
    }

    addRule(rule:(linkNode:LinkNode)=>boolean){
        this.rules.push(rule)
    }

    removeRule(rule:(linkNode:LinkNode)=>boolean){
        const i = this.rules.indexOf(rule)
        this.rules.splice(i, 1)
    }

    active(){
        this.background(this.bgColor)
    }

    cancelActive(){
        this.linkNodeLines.length || this.background('none')
    }

    linkNodeEnter({rule}:{rule: boolean}){
        if(rule){
            this.border('solid 1px #37ff3f')
        }
        else{
            this.border('solid 1px red')
        }
    }

    linkNodeLeave({rule}:{rule: boolean}){
        this.border('solid 1px ' + this.bgColor)
    }

    createLinkNodeLine(targetLinkNode: LinkNode | GraphNode, linkNodeName?: string){
        if(targetLinkNode instanceof LinkNode){
            const linkNodeLine: LinkNodeLine = new LinkNodeLine()
            linkNodeLine.drawTarget(this.graphView)
            linkNodeLine?.path.pointerEvents('all')
            this.linkNodeLineEvent( linkNodeLine )

            this.linkNodeLines.push( linkNodeLine )
            this.update()
            this.active()
            targetLinkNode.linkNodeLines.push( linkNodeLine )
            targetLinkNode.update()
            targetLinkNode.active()

            if(this.index === 0){
                linkNodeLine.startPointTarget = targetLinkNode
                linkNodeLine.endPointTarget = this
            }
            else{
                linkNodeLine.startPointTarget = this
                linkNodeLine.endPointTarget = targetLinkNode
            }

            linkNodeLine.path.stroke(this.bgColor)

            this.count++
            targetLinkNode.count++
        }
        else if(targetLinkNode instanceof GraphNode){
            const linkNodeEnter = targetLinkNode.enters[linkNodeName as string]
            this.createLinkNodeLine( linkNodeEnter )
        }
    }

    export(){
        return this.linkNodeLines.map(
            linkNodeLine=>linkNodeLine.getLinkTargetUuid(this.index)
        )
    }

    closeAll(){
        this.linkNodeLines.forEach(linkNodeLine=> linkNodeLine.del())
    }
}


const flowIcon = `<svg t="1701593345792" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10752" width="100%" height="100%">
    <path d="M836.510807 434.657683C656.703466 297.433771 476.896125 160.20986 297.110458 22.964274 233.074559-25.888544 140.812869 19.758235 140.812869 100.306592v823.38501c0 80.548357 92.26169 126.196941 156.297589 77.322449 179.785667-137.225717 359.593008-274.447822 539.400349-411.691602 51.01125-38.933061 51.01125-115.711837 0-154.664766z" p-id="10753"></path>
</svg>`
export class LinkNodeRightArrow extends LinkNode {
    constructor(graphNode: GraphNode, graphView: GraphView){
        super(graphNode, graphView)
        this.setHtml(flowIcon)
        this.displyFlex()
        this.setStyle({
            alignItems: 'center',
            justifyContent: 'center',
            border: 'none',
            fill: 'gray',
            width: '15px',
            height: '15px',
            transition: '0.25s'
        })
    }

    setIndex(index: 0 | 1){
        this.index = index
        if(index === 1){
            this.setStyle({
                transform: "rotateZ(180deg)"
            })
        }
    }

    setBgColor(color: string){
        this.bgColor = color
    }

    active(){
        this.setStyle({
            fill: "#fff",
        })
    }

    cancelActive(){
        this.linkNodeLines.length || this.setStyle({
            fill: "gray",
        })
    }

    linkNodeEnter({rule}:{rule: boolean}){
        if(rule){
            this.setStyle({
                fill: "#37ff3f",
            })
        }
        else{
            this.setStyle({
                fill: "red",
            })
        }
    }

    linkNodeLeave({rule}:{rule: boolean}){
        this.setStyle({
            fill: "gray",
        })
    }
}